Skip to content

fix: derive semantic theme tokens on the dashboard theme boundary - #9811

Merged
nishantmonu51 merged 3 commits into
mainfrom
nishant/fix-dashboard-theme-semantic-tokens
Sep 4, 2026
Merged

nishantmonu51 merged 3 commits into
mainfrom
nishant/fix-dashboard-theme-semantic-tokens

Conversation

@nishantmonu51

Copy link
Copy Markdown
Collaborator

app.css declares the hover, accent, focus-ring, dimension and measure tokens on :root, against Rill's own primary/secondary palettes:

:root {
  --surface-hover: var(--color-primary-50);
  --popover-accent: var(--surface-hover);
  --ring-focus: var(--color-theme-300);
  /* ...accent-*, icon-accent, fg-accent, dimension-*, measure-* */
}

A custom property's var() references are substituted at the element that declares it, so these always resolve against the default palette. A dashboard theme is scoped to .dashboard-theme-boundary further down the tree, so it can never reach them — Rill's indigo leaks into hover, selection, focus rings and dimension/measure chips on a rethemed dashboard, even though --color-theme-* itself is correct.

  • Re-declare the affected tokens on the boundary from the theme's own palettes. The shades mirror app.css exactly (PALETTE_DERIVED_TOKENS), so only the hue source changes, not the design.
  • Dark mode keeps its neutral gray surfaces: surface-hover/surface-active/popover-accent are emitted as unset so the boundary inherits :root.dark. Dark accents read the light-palette shades, matching what :root.dark does.
  • Alias --color-primary-* and --color-secondary-* to the theme's palettes inside the boundary, so the ~300 bg-primary-500-style utilities in dashboard components follow the theme without each one being migrated. Outside the boundary — nav, file explorer, admin chrome — Rill's brand colors are untouched.
  • Explicit variables: in the theme YAML still win, and a theme that sets fg-primary keeps ownership of fg-accent.

Worth a look during review: this now themes the dimension and measure chips as well. That is the intended behaviour for brand adherence, but it is the most visible change beyond hover and selection.

Reported for explore leaderboards, where hover (bg-popover-accent) and excluded bars (var(--surface-active)) stayed purple under a custom theme. The fix is at the token level, so it clears the same leak in dropdowns, pivot rows, the TDD table and filter chips at the same time.

Checklist:

  • Covered by tests
  • Ran it and it works as intended
  • Reviewed the diff before requesting a review
  • Checked for unhandled edge cases
  • Linked the issues it closes
  • Checked if the docs need to be updated. If so, create a separate Linear DOCS issue
  • Intend to cherry-pick into the release branch
  • I'm proud of this work!

app.css declares the hover, accent, focus-ring, dimension and measure tokens
on :root against Rill's own primary/secondary palettes. Custom properties are
substituted at the element that declares them, so those tokens always resolve
to the default palette and a dashboard theme -- scoped to
.dashboard-theme-boundary -- can never influence them. Rill's indigo leaked
into hover, selection and chips on rethemed dashboards.

Re-declare the affected tokens on the boundary from the theme's own palettes,
using the same shades app.css picks, and alias --color-primary-*/--color-secondary-*
there too so the `bg-primary-500`-style utilities in dashboard components follow
the theme without each one having to be migrated.

Claude-Session: https://claude.ai/code/session_0185gM7SaxBvfaR2Tt79sXA7
- Keep dark mode's own `fg-primary` in charge of `fg-accent`. The light block
  now derives `fg-accent`, and generateCSS backfilled it into the dark block as
  `unset`, which both reset the token to Rill's indigo and suppressed the
  `fg-*` hierarchy value stringifyVars would have generated.
- Allow `dimension*` and `measure*` as theme variables in the parser, so a
  theme author who wants the hover and accent fix but neutral chips can opt out
  of the derived values. They were rejected as invalid CSS variables before.
- Resolve the plain `--color-primary-N` alias in themeManager.resolveCSSVariable.
  It only looked for the `-light-`/`-dark-` forms on the boundary, which the
  boundary never emits, so Vega charts kept Rill's indigo while chart colors
  resolved through charts/util.ts followed the theme.
- Carry the boundary class into portalled dialogs, as the other portalled
  surfaces already do. Dialogs opened from a themed dashboard kept the default
  `popover-accent`, `surface-hover` and `ring-focus`.

Claude-Session: https://claude.ai/code/session_012EKEx36KxQeZ11MzSML2tn
Comment thread web-common/src/features/themes/theme.ts
Comment thread web-common/src/features/themes/theme.ts
@nishantmonu51 nishantmonu51 added Type:Bug Something isn't working Area:Dashboard Size:M Medium change: 100-499 lines labels Sep 4, 2026
@nishantmonu51
nishantmonu51 merged commit feb5f7a into main Sep 4, 2026
15 checks passed
@nishantmonu51
nishantmonu51 deleted the nishant/fix-dashboard-theme-semantic-tokens branch September 4, 2026 16:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area:Dashboard Size:M Medium change: 100-499 lines Type:Bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants